/*
*	Random Sentence Realizer
*
*   @author: Sampat Biswas
*   Copyright 2011 Sampat Biswas
*
*   This file is part of Sentence-Realizer.
*
*   Sentence-Realizer is free software: you can redistribute it and/or modify
*   it under the terms of the GNU General Public License as published by
*   the Free Software Foundation, either version 3 of the License, or
*   (at your option) any later version.
*
*   Sentence-Realizer is distributed in the hope that it will be useful,
*   but WITHOUT ANY WARRANTY; without even the implied warranty of
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*   GNU General Public License for more details.
*
*   You should have received a copy of the GNU General Public License
*   along with Sentence-Realizer.  If not, see <http://www.gnu.org/licenses/>.
*	
*
*/

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Stack;

public class RandomSentenceRealizer {
	
	static ArrayList<ArrayList<String>> _Noun = new ArrayList<ArrayList<String>>(); 
	static ArrayList<ArrayList<String>> _Verb = new ArrayList<ArrayList<String>>(); 
	static ArrayList<ArrayList<String>> _Adjective = new ArrayList<ArrayList<String>>();
	static ArrayList<ArrayList<String>> _Determiner = new ArrayList<ArrayList<String>>();
	static ArrayList<ArrayList<String>> _Auxuliary = new ArrayList<ArrayList<String>>();
	static ArrayList<ArrayList<String>> _Preposition = new ArrayList<ArrayList<String>>();
	static ArrayList<ArrayList<String>> _Adverb = new ArrayList<ArrayList<String>>();
	static ArrayList<ArrayList<String>> _Demonstrative = new ArrayList<ArrayList<String>>();
	static ArrayList<ArrayList<String>> _Quantifier = new ArrayList<ArrayList<String>>();
	
	
	static HashMap<String, ArrayList<ArrayList<String>>> _Lexicon = new HashMap<String, ArrayList<ArrayList<String>>>();
	
	static HashMap<String, ArrayList<String>> _Grammar = new HashMap<String, ArrayList<String>>();
	
	static HashMap<String, String> _Punctuation = new HashMap<String, String>();
	
	static final String PERIOD = "Period";
	static final String PERIOD_SYMBOL = ".";
	static final String QUESTION = "Question";
	static final String QUESTION_SYMBOL = "?";
	static final String COMMA = "Comma";
	static final String COMMA_SYMBOL = ",";
	static final String EXCLAMATION = "Exclamation";
	static final String EXCLAMATION_SYMBOL = "!";
	
	
	
	static Stack<String> sentenceStack = new Stack<String>();
	
	static int number = -1;
	static String sentenceEndType = PERIOD;
	static boolean isPunctuationSet=false;
	static boolean isFirstPrint=true;
	
	
	public static void main(String[] args) {
		
		/**
		 *  Construct the Lexicon
		 */
		
		// Populate Noun, Verb & Adjective
		
		String[] nouns = {"man s", "men p", "bird s", "birds p", "house s", "houses p", "car s", "cars p", "book s", "books p", "apple s", "apples p"};
		String[] verbs = {"runs s", "run p", "eats s", "eat p", "flies s", "fly p", "drives s", "drive p", "dreams s", "dream p", "walks s", "walk p"};
		String[] adjectives = {"fast s", "fast p", "slow s", "slow p", "happy s", "happy p"};
		String[] determiners = {"the s", "  p", "a s", "  p"};
		String[] auxuliary = {"can p", "can p", "may p", "may p", "will p", "will p"};
		String[] prepositions = {"in s", "in p", "on s", "on p", "with s", "with p"};
		String[] adverbs = {"happily s", "happily p", "easily s", "easily p"};
		String[] demonstratives = {"this s", "these p", "that s", "those p"};
		String[] quantifiers = {"some p", "some p", "many p", "many p"};
		
		populate(nouns, "N");
		populate(verbs, "V");
		populate(adjectives, "Aj");
		populate(determiners, "D");
		populate(auxuliary, "Aux");
		populate(prepositions, "P");
		populate(adverbs, "Adv");
		populate(demonstratives, "Dem");
		populate(quantifiers, "Quant");
		
		
		// Add Noun, Verb & Adjective list to the Lexicon
		
		_Lexicon.put("N", _Noun);
		_Lexicon.put("V", _Verb);
		_Lexicon.put("Aj", _Adjective);
		_Lexicon.put("D", _Determiner);
		_Lexicon.put("Aux", _Auxuliary);
		_Lexicon.put("P", _Preposition);
		_Lexicon.put("Adv", _Adverb);
		_Lexicon.put("Dem", _Demonstrative);
		_Lexicon.put("Quant", _Quantifier);
		
		
		
		/**
		 *  Construct the Grammar
		 */
		
		ArrayList<String> S_rule = new ArrayList<String>();
		S_rule.add("NP VP");
		S_rule.add("Aux NP VP");
		S_rule.add("NP Aux VP");
		
		ArrayList<String> NP_rule = new ArrayList<String>();
		NP_rule.add("Aj N");
		NP_rule.add("D Aj N");
		NP_rule.add("D Aj N PP");
		NP_rule.add("N PP");
		NP_rule.add("Dem N");
		NP_rule.add("Quant N");
		
		ArrayList<String> VP_rule = new ArrayList<String>();
		VP_rule.add("V");
		VP_rule.add("V Adv");
		
		ArrayList<String> PP_rule = new ArrayList<String>();
		PP_rule.add("P NP");
		
		_Grammar.put("S", S_rule);
		_Grammar.put("NP", NP_rule);
		_Grammar.put("VP", VP_rule);
		_Grammar.put("PP", PP_rule);
		
		
		// Populate punctuation symbols
		_Punctuation.put(PERIOD, PERIOD_SYMBOL);
		_Punctuation.put(QUESTION, QUESTION_SYMBOL);
		_Punctuation.put(COMMA, COMMA_SYMBOL);
		_Punctuation.put(EXCLAMATION, EXCLAMATION_SYMBOL);
		
		
		
		String input = "S";
		
		sentenceStack.push(input);
		
		Generate();
		
	}
	
	private static void Generate() {
		while(sentenceStack.size() != 0) {
			// Pop the top of stack
			String item = sentenceStack.pop();
			
			// If item is a lexical term, Print it
			if(_Lexicon.containsKey(item)) {
				ArrayList<ArrayList<String>> list = _Lexicon.get(item);
				int randomIndex = (int) (Math.random() * list.size());
				ArrayList<String> randomElem = list.get(randomIndex);
				if(number < 0) {
					int rnd = (int) (Math.random() * randomElem.size());
					if(randomElem.get(rnd).split(" ")[1].equals("s")) {
						number = 1;
					}
					else {
						number = 2;
					}
				}
				
				if(number == 1) {
					if(isFirstPrint) {
						String wordToPrint = randomElem.get(0).split(" ")[0];
						System.out.print(wordToPrint.substring(0, 1).toUpperCase() + wordToPrint.substring(1) + " ");
						isFirstPrint=false;
					} else 
						System.out.print(randomElem.get(0).split(" ")[0]+" ");
				}
				else if(number == 2) {
					if(isFirstPrint) {
						String wordToPrint = randomElem.get(1).split(" ")[0];
						System.out.print(wordToPrint.substring(0, 1).toUpperCase() + wordToPrint.substring(1) + " ");
						isFirstPrint=false;
					} else 
						System.out.print(randomElem.get(1).split(" ")[0]+" ");
				}
			}
			
			// Otherwise, call Expand with item and Push the result onto top of stack
			else {
				String tokens[] = Expand(item).split(" ");
				for(int i=tokens.length-1; i>=0; i--){
					sentenceStack.push(tokens[i]);
				}
			}
			
		}
		
		System.out.println(_Punctuation.get(sentenceEndType));
	}
	
	private static String Expand(String key) {
		// if key is a word class in the lexicon, return a word randomly selected from that class
		if(_Lexicon.containsKey(key)) {
			ArrayList<ArrayList<String>> list = _Lexicon.get(key);
			int randomIndex = (int) (Math.random() * list.size());
			ArrayList<String> randomElem = list.get(randomIndex);
			if(number < 0) {
				int rnd = (int) (Math.random() * randomElem.size());
				String rElem = randomElem.get(rnd);
				if(rElem.split(" ")[1].equals("s")) {
					number = 1;
				}
				else {
					number = 2;
				}
			}
			if(number == 1) {
				return randomElem.get(0);
			}
			else if(number == 2) {
				return randomElem.get(1);
			}
			
		}
		
		// if key is a the head of a grammar rule, return an expansion randomly chosen from that rule
		if(_Grammar.containsKey(key)) {
			ArrayList<String> list = _Grammar.get(key);
			int randomIndex = (int) (Math.random() * list.size());
			// Set punctuation mark
			if(!isPunctuationSet) {
				if(key.equals("S") && list.get(randomIndex).startsWith("Aux")) {
					sentenceEndType = QUESTION;
					isPunctuationSet=true;
				}
			}
			return list.get(randomIndex);
		}
		
		System.out.println("Error!");
		return "";
	}
	
	private static void populate(String[] a, String type) {
		ArrayList<ArrayList<String>> ref=null;
		if(type.equals("N")) {
			ref = _Noun;
		}
		else if(type.equals("V")) {
			ref = _Verb;
		}
		else if(type.equals("Aj")) {
			ref = _Adjective;
		}
		else if(type.equals("D")) {
			ref = _Determiner;
		}
		else if(type.equals("Aux")) {
			ref = _Auxuliary;
		}
		else if(type.equals("P")) {
			ref = _Preposition;
		}
		else if(type.equals("Adv")) {
			ref = _Adverb;
		}
		else if(type.equals("Dem")) {
			ref = _Demonstrative;
		}
		else if(type.equals("Quant")) {
			ref = _Quantifier;
		}
		
		for(int i=0; i<a.length;) {
			ArrayList<String> elem = new ArrayList<String>();
			elem.add(a[i]);elem.add(a[i+1]);
			ref.add(elem);
			i+=2;
		}
	}
}